/*
    This file is part of SQLiteGTK, written by Aly Hirani

    SQLiteGTK is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    SQLiteGTK is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with SQLiteGTK.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "util.h"
#include "include.h"
#include <stdarg.h>
#include <glib/gstdio.h>

#ifdef ENABLE_SOURCE_VIEW
GtkSourceLanguage *source_lang = NULL;
GtkSourceLanguageManager *source_lang_manager = NULL;
GtkSourceStyleScheme *source_style_scheme = NULL;
GtkSourceStyleSchemeManager *source_style_scheme_manager = NULL;
GRegex *hint_regex = NULL;
#endif /* ENABLE_SOURCE_VIEW */

guint total_windows = 0;
PrefsManager *prefs_manager = NULL;
GtkClipboard *selection_clipboard = NULL;

void
log_verbose(const gchar *format, ...)
{
	va_list args;
	va_start( args, format );
	g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format, args);
	va_end( args );
}

void
log_message(const gchar *format, ...)
{
	va_list args;
	va_start( args, format );
	g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args);
	va_end( args );
}

void
log_warning(const gchar *format, ...)
{
	va_list args;
	va_start( args, format );
	g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
	va_end( args );
}

void
log_error(const gchar *format, ...)
{
	va_list args;
	va_start( args, format );
	g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args);
	va_end( args );
}

gchar*
show_file_dialog(GtkWindow *parent_window, const gchar *title, MessageDialogType dialog_type, const gchar *filter_name,
	const gchar *filter_mimetype, const gchar *filter_pattern)
{
	GtkWidget *dialog;
	gchar *file_path;
	
	g_assert(parent_window != NULL);
	g_assert(title != NULL);
	
	if(filter_name)
		g_assert(filter_mimetype || filter_pattern);
	
	log_verbose("Entering show_create_file_dialog");
	
	dialog = gtk_file_chooser_dialog_new (title, parent_window,
		(dialog_type == MDT_FILE_OPEN ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE), 
		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, (dialog_type == MDT_FILE_OPEN ? GTK_STOCK_OPEN : GTK_STOCK_NEW), 
		GTK_RESPONSE_ACCEPT, NULL);
	g_assert(dialog != NULL);
	
#ifndef DISABLE_GTK_FILE_CHOOSER_WINDOW_SIZE_BUG
	/* Workaround for the stupid bug */
	gtk_window_set_default_size(GTK_WINDOW(dialog), 804, 600);
#endif /* DISABLE_GTK_FILE_CHOOSER_WINDOW_SIZE_BUG */

	file_path = NULL;
	
	if(filter_name)
	{
		GtkFileFilter *filter = gtk_file_filter_new();
		gtk_file_filter_set_name(filter, filter_name);
		if(filter_mimetype)
			gtk_file_filter_add_mime_type(filter, filter_mimetype);
		if(filter_pattern)
			gtk_file_filter_add_pattern(filter, filter_pattern);
		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
	}
	
	if(dialog_type == MDT_FILE_SAVE)
		gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
	
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{
		file_path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
	}
	
	gtk_widget_destroy (dialog);
	
	return file_path;
}

gboolean
delete_file(const gchar *file_path)
{
	GFile *file;
	gboolean result;
	
	g_assert(file_path != NULL);
	
	file = g_file_new_for_path(file_path);
	g_assert(file != NULL);
	
	result = TRUE;
	
	if(g_file_query_exists(file, NULL))
	{
		if(!g_file_delete(file, NULL, NULL))
		{
			log_warning("Unable to delete %s", file_path);
			result = FALSE;
		}
	}
	
	g_object_unref(file);
	
	return result;
}

gchar *
get_app_data_path(const gchar* pref_name)
{
	gchar *pref_path, *pref_dir;
	GDir *dir;
	
	pref_path = g_build_path ("/", g_get_user_config_dir(), "sqlitegtk", pref_name, NULL);
	R_ASSERT(pref_path != NULL);
	
	pref_dir = g_path_get_dirname(pref_path);
	R_ASSERT(pref_dir != NULL);
	
	dir = g_dir_open(pref_dir, 0, NULL);
	if(dir == NULL)
	{
		gint result = g_mkdir(pref_dir, S_IRWXU | S_IRWXG | S_IRWXO);
		R_ASSERT(result == 0);
	}
	else
	{
		g_dir_close(dir);
	}
	
	g_free(pref_dir);
	return pref_path;
}

#ifdef ENABLE_SOURCE_VIEW
void
set_buffer_file_path(GtkSourceBuffer *buffer, const gchar *file_path)
{
	g_assert(buffer != NULL);
	
	g_object_set_data_full(G_OBJECT(buffer), BUFFER_FILE_PATH_KEY, g_strdup(file_path), (GDestroyNotify)g_free);
}

gchar*
get_buffer_file_path(const GtkSourceBuffer *buffer)
{
	g_assert(buffer != NULL);
	
	return g_object_get_data(G_OBJECT(buffer), BUFFER_FILE_PATH_KEY);
}

void
init_source_lang(const gchar *file_name, const gchar *mime_type)
{
	if(!file_name && !mime_type)
		return;
	
	source_lang_manager = gtk_source_language_manager_new();
	g_assert(source_lang_manager != NULL);
	g_object_ref(source_lang_manager);
	
	source_lang = gtk_source_language_manager_guess_language(source_lang_manager, file_name, mime_type);
}

void
init_source_style(const gchar *id)
{
	gchar *app_style_path;
	if(!id)
		return;
	
	source_style_scheme_manager = gtk_source_style_scheme_manager_new();
	g_assert(source_style_scheme_manager != NULL);
	g_object_ref(source_style_scheme_manager);
	
	app_style_path = get_app_data_path("styles");
	g_assert(app_style_path != NULL);
	gtk_source_style_scheme_manager_append_search_path(source_style_scheme_manager, app_style_path);
	g_free(app_style_path);	
	
	source_style_scheme = gtk_source_style_scheme_manager_get_scheme(source_style_scheme_manager, id);
}
#endif /* ENABLE_SOURCE_VIEW */

void
init_app()
{
	gchar *prefs_manager_path;

	prefs_manager_path = get_app_data_path("prefs.ini");
	g_assert(prefs_manager_path != NULL);
	
	prefs_manager = prefs_manager_new(prefs_manager_path);
	
	g_free(prefs_manager_path);
}

void
uninit_app()
{
	prefs_manager_free(prefs_manager);

#ifdef ENABLE_SOURCE_VIEW
	uninit_main_window_notebook_source_view();
#endif /* ENABLE_SOURCE_VIEW */
}


gint
show_message_dialog(GtkWindow *parent, GtkDialogFlags flags, 
	GtkMessageType type, GtkButtonsType buttons, gint default_response_id, const gchar *message_format, ...)
{
	/*
	va_list args;
	va_start(args, message_format);
	
	gchar *message = g_strdup_vprintf(message_format, args);
	g_assert(message != NULL);
	
	GtkDialog *dialog = GTK_DIALOG(gtk_message_dialog_new(parent, flags, type, buttons, "%s", message));
	g_assert(dialog != NULL);
	
	gtk_dialog_set_default_response(dialog, default_response_id);
	
	gint result = gtk_dialog_run(dialog);
	
	g_free(message);
	gtk_widget_destroy(GTK_WIDGET(dialog));
	va_end(args);
	return result;
	*/
	
	return -1;
}

void
remove_tree_view_columns_for_each(gpointer data, gpointer user_data)
{
	/*
	g_assert(data != NULL);
	g_assert(user_data != NULL);
	
	GtkTreeView *tree_view = GTK_TREE_VIEW(user_data);
	g_assert(tree_view != NULL);
	
	GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(data);
	g_assert(column != NULL);
	
	gtk_tree_view_remove_column(tree_view, column);
	*/
}

size_t g_ascii_strlen(const gchar* str)
{
	return strlen(str);
}

/* The glib library, for some reason, has this as non-const. This is a workaround to fixing that stupidity */
inline guint sqlite_strv_length(const gchar **str_array)
{
	return g_strv_length((gchar**)str_array);
}

/* Copies the string until the given ptr to the last char. The last char is not copied */
/* As freaking fast as possible */
inline gchar *strdupptr(const gchar *str, const gchar *end)
{
	gsize len;
	gchar *new_str;

	/* 1 for the NULL terminator. 1 for the fact that subtraction is an operation of type (str,end], rather than [str,end] (mathematical range notation) */
	D_ASSERT(str);
	D_ASSERT(end);

	if(!*end)
	{
		/* If we are at the end of the string, just do an strdup */
		return g_strdup(str);
	}

	len = end-str+1;
	new_str = g_malloc(len);
	R_ASSERT(new_str);

	memcpy(new_str, str, len-1);
	new_str[len-1] = '\0';

	return new_str;
}

/* Hack! I don't want to even write this simple function. I am too lazy */
guint voidv_length(void **array)
{
	return g_strv_length((gchar**)array);
}
